package SerialTest1;

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

import java.net.*;

public class TCPServer implements Runnable {
   // Connect status constants
   public final static int NULL = 0;
   public final static int DISCONNECTED = 1;
   public final static int DISCONNECTING = 2;
   public final static int BEGIN_CONNECT = 3;
   public final static int CONNECTED = 4;
   // Other constants
   public final static TCPServer tcpObj = new TCPServer();
   public final static String END_CHAT_SESSION = String.valueOf(new Character((char) 0));
   // Indicates the end of a session

   // Connection state info
   public static String serverIP = "localhost";
   public static int port = 1234;
   public static int connectionStatus = DISCONNECTED;

   // Various GUI components and info
   public static JTextField portField = null;
   public static JButton listenButton = null;
   public static JButton disconnectButton = null;
   public static JButton clearButton = null;

   // TCP Components
   public static ServerSocket svrsocket;
   public static Socket socket;
   public static BufferedReader in;
   public static PrintWriter out = null;
   public static StringBuffer sendString = new StringBuffer("");

   // ///////////////////////////////////////////////////////////////

   // Cleanup for disconnect
   private static void cleanUp() {
      try {
         if (svrsocket != null) {
            svrsocket.close();
            svrsocket = null;
         }
      } catch (IOException e) {
         svrsocket = null;
      }

      try {
         if (socket != null) {
            socket.close();
            socket = null;
         }
      } catch (IOException e) {
         socket = null;
      }

      try {
         if (in != null) {
            in.close();
            in = null;
         }
      } catch (IOException e) {
         in = null;
      }

      if (out != null) {
         out.close();
         out = null;
      }
   }

   // ///////////////////////////////////////////////////////////////

   // Checks the current state and sets the enables/disables
   // accordingly
   public void run() {
      switch (connectionStatus) {
      case DISCONNECTED:
         listenButton.setEnabled(true);
         disconnectButton.setEnabled(false);
         portField.setEnabled(true);
         break;

      case DISCONNECTING:
         listenButton.setEnabled(false);
         disconnectButton.setEnabled(false);
         portField.setEnabled(false);
         break;

      case CONNECTED:
         listenButton.setEnabled(false);
         disconnectButton.setEnabled(true);
         portField.setEnabled(false);
         break;

      case BEGIN_CONNECT:
         listenButton.setEnabled(false);
         disconnectButton.setEnabled(false);
         portField.setEnabled(false);
         break;
      }

      // Make sure that the button/text field states are consistent
      // with the internal states
      portField.setText(String.valueOf((new Integer(port))));
   }

   // /////////////////////////////////////////////////////////////////////

   public JPanel OptionsPane() {
      JPanel pane = null;
      ActionListener buttonListener = null;

      // Create an options pane
      JPanel optionsPane = new JPanel(new BorderLayout(10, 20));

      // Port input
      pane = new JPanel(new FlowLayout(FlowLayout.LEFT));
      pane.add(new JLabel("Port : "));
      portField = new JTextField(10);
      portField.setEditable(true);
      portField.setText(String.valueOf((new Integer(port))));
      portField.addFocusListener(new FocusAdapter() {
         public void focusLost(FocusEvent e) {
            // should be editable only when disconnected
            if (connectionStatus != DISCONNECTED) {
               tcpObj.run();
            } else {
               int temp;
               try {
                  temp = Integer.parseInt(portField.getText());
                  port = temp;
               } catch (NumberFormatException nfe) {
                  portField.setText(String.valueOf((new Integer(port))));
               }
            }
         }
      });
      pane.add(portField);
      optionsPane.add(pane, "North");

      // Connect/Disconnect buttons
      JPanel buttonPane = new JPanel(new GridLayout(1, 2));
      buttonListener = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            // Request a connection initiation
            if (e.getActionCommand().equals("Listen")) {
               try {
                  svrsocket = new ServerSocket(port);
                  socket = svrsocket.accept();
                  connectionStatus = CONNECTED;

                  tcpObj.run();
               } catch (IOException e1) {
                  // TODO Auto-generated catch block
                  e1.printStackTrace();
               }
            }
            // Disconnect
            else {
               // Clean up (close all streams/sockets)
               cleanUp();
               connectionStatus = DISCONNECTED;

               tcpObj.run();
            }
         }
      };
      listenButton = new JButton("Listen");
      listenButton.setMnemonic(KeyEvent.VK_C);
      listenButton.setActionCommand("Listen");
      listenButton.addActionListener(buttonListener);
      listenButton.setEnabled(true);
      disconnectButton = new JButton("Disconnect");
      disconnectButton.setMnemonic(KeyEvent.VK_D);
      disconnectButton.setActionCommand("Disconnect");
      disconnectButton.addActionListener(buttonListener);
      disconnectButton.setEnabled(false);
      buttonPane.add(listenButton);
      buttonPane.add(disconnectButton);
      optionsPane.add(buttonPane, "South");

      return optionsPane;
   }

   public void settingRun() {
      String s = "";

      if (connectionStatus == CONNECTED) {
         try {
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream());
         } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
         }
         while (true) {
            try { // Poll every ~1 ms
               Thread.sleep(1);
            } catch (InterruptedException e) {
            }

            try {
               // Send data
               if (sendString.length() != 0) {
                  out.println(String.valueOf(sendString));
                  out.flush();
                  sendString.setLength(0);
                  SwingUtilities.invokeLater(tcpObj);
               }

               // Receive data
               if (in.ready()) {
                     s = in.readLine();
                     ChatGUI.receiveData(s.getBytes());
                     SwingUtilities.invokeLater(tcpObj);
               }
            } catch (IOException e) {
               cleanUp();
               connectionStatus = DISCONNECTED;
               SwingUtilities.invokeLater(tcpObj);
            } catch (NullPointerException ne){
               cleanUp();
               connectionStatus = DISCONNECTED;
               SwingUtilities.invokeLater(tcpObj);
            }
         }
      }
   }
   
   public static void sendString(StringBuffer s){
      sendString = s;
   }
   
   // The main
   public static void main(String[] args) {
      new TCPServer();
   }
}